#include "drv_l1_cache.h"
#include "drv_l1_rotator.h"
#include "drv_l1_gpio.h"

#if (defined _DRV_L1_ROTATOR) && (_DRV_L1_ROTATOR == 1)
typedef struct
{	// Offset
	volatile INT32U ROTATOR_BUF_I_ADDR;		// 0x0000
	volatile INT32U ROTATOR_BUF_O_ADDR;		// 0x0004
	volatile INT32U ROTATOR_IMG_WIDTH;		// 0x0008
	volatile INT32U ROTATOR_IMG_HEIGHT;		// 0x000C
	volatile INT32U ROTATOR_CTRL;			// 0x0010
	volatile INT32U ROTATOR_START;			// 0x0014
	volatile INT32U ROTATOR_IRQ_STATUS;		// 0x0018
	volatile INT32U ROTATOR_IRQ_EN;			// 0x001C
	volatile INT32U ROTATOR_BUF_I_ADDR2;	// 0x0020
	volatile INT32U ROTATOR_SW_RESET;		// 0x0024
} ROTATOR_SFR;

// control register
#define C_RPTATOR_START			0x00000001
#define C_RPTATOR_INT_END		C_RPTATOR_START
#define C_RPTATOR_INT_EN		C_RPTATOR_START

#define PIXEL_W_BIT				(0)
#define PIXEL_W_MASK			(0xFFF << PIXEL_W_BIT)
#define PIXEL_H_BIT				(0)
#define PIXEL_H_MASK			(0xFFF << PIXEL_H_BIT)
#define ROT_MODE_BIT			(0)
#define ROT_MODE_MASK			(0x7 << ROT_MODE_BIT)
#define ROT_MODE_90				(0x0 << ROT_MODE_BIT)
#define ROT_MODE_180			(0x1 << ROT_MODE_BIT)
#define ROT_MODE_270			(0x2 << ROT_MODE_BIT)
#define ROT_MODE_H_MIRR			(0x3 << ROT_MODE_BIT)
#define ROT_MODE_V_MIRR			(0x4 << ROT_MODE_BIT)
#define ROT_MODE_270_V_MIRR		(0x5 << ROT_MODE_BIT)
#define ROT_MODE_90_V_MIRR		(0x6 << ROT_MODE_BIT)
#define YUV422_BIT				(4)
#define YUV422_MASK				(0x3 << YUV422_BIT)
#define YUV422_YUYV				(0x0 << YUV422_BIT)
#define YUV422_YVYU				(0x1 << YUV422_BIT)
#define YUV422_UYVY				(0x2 << YUV422_BIT)
#define YUV422_VYUY				(0x3 << YUV422_BIT)
#define BUFFER_MODE_BIT			(9)
#define BUFFER_MODE_MASK		(0x1 << BUFFER_MODE_BIT)
#define BUFFER_MODE_SHADOW		(0x0 << BUFFER_MODE_BIT)
#define BUFFER_MODE_AB			(0x1 << BUFFER_MODE_BIT)
#define ROT_MODULE_BIT			(11)
#define ROT_MODULE_MASK			(0x1 << ROT_MODULE_BIT)
#define ROT_MODULE_DISABLE		(0x0 << ROT_MODULE_BIT)
#define ROT_MODULE_ENABLE		(0x1 << ROT_MODULE_BIT)
#define FORMAT_BIT				(12)
#define FORMAT_MASK				(0x3 << FORMAT_BIT)
#define FORMAT_GP420			(0x0 << FORMAT_BIT)
#define FORMAT_YUV422			(0x1 << FORMAT_BIT)
#define FORMAT_RGB565			(0x2 << FORMAT_BIT)
#define ROT_BURST_BIT			(16)
#define ROT_BURST_MASK			(0x1 << ROT_BURST_BIT)
#define ROT_BURST_8				(0x0 << ROT_BURST_BIT)
#define ROT_BURST_16			(0x1 << ROT_BURST_BIT)
#define ROT_BUFFER_MODE_SHADOW	0
#define ROT_BUFFER_MODE_AB		1
#define ROT_SW_RESET_BIT		(0)
#define ROT_SW_RESET_SET		(0x1 << ROT_SW_RESET_BIT)

#define C_ROTATOR_QUEUE_SIZE	5
#define C_ROTATOR_END			1
#define GPM4_ROT_BUG_EN			0

#if _OPERATING_SYSTEM == _OS_UCOS2
#define SYSTEM_OS_ENABLE	1
#elif _OPERATING_SYSTEM == _OS_FREERTOS
#define SYSTEM_OS_ENABLE	2
#else
#define SYSTEM_OS_ENABLE	0
#endif
#if SYSTEM_OS_ENABLE == 1
OS_EVENT		*rotator_q = NULL;
OS_EVENT		*rotator_hw_sem = NULL;
void			*rotator_q_buffer[C_ROTATOR_QUEUE_SIZE];
#elif SYSTEM_OS_ENABLE == 2
osMessageQId	rotator_q = NULL;
osSemaphoreId	rotator_hw_sem = NULL;
#else
static INT32U	rotator_end;
#endif
static void (*_isr_hook) (void) = 0;

/*****************************************************
* get_ROTATOR_Reg_Base:
*
*****************************************************/
static __inline ROTATOR_SFR *get_ROTATOR_Reg_Base(void)
{
	return (ROTATOR_SFR *) ROTATOR_BASE;
}

static void drv_l1_rotator_lock(void)
{
#if SYSTEM_OS_ENABLE == 1
	INT8U	err;
	if(rotator_hw_sem)
		OSSemPend(rotator_hw_sem, 0, &err);
#elif SYSTEM_OS_ENABLE == 2
	if(rotator_hw_sem)
		osSemaphoreWait(rotator_hw_sem, osWaitForever);
#endif
}

static void drv_l1_rotator_unlock(void)
{
#if SYSTEM_OS_ENABLE == 1
	if(rotator_hw_sem)
		OSSemPost(rotator_hw_sem);
#elif SYSTEM_OS_ENABLE == 2
	if(rotator_hw_sem)
		osSemaphoreRelease(rotator_hw_sem);
#endif
}

static void rotator_isr(void)
{
	get_ROTATOR_Reg_Base()->ROTATOR_IRQ_STATUS = C_RPTATOR_INT_END;

#if SYSTEM_OS_ENABLE == 1
	if(rotator_q)
		OSQPost(rotator_q, (void *) C_ROTATOR_END);
#elif SYSTEM_OS_ENABLE == 2
	if(rotator_q)
	{
		INT32U	event;

		event = C_ROTATOR_END;
		osMessagePut(rotator_q, (uint32_t) & event, osWaitForever);
	}

#else
	rotator_end = 0;
#endif
}

void ROTATOR_IRQHandler(void)
{
	rotator_isr();
	if(_isr_hook)
	{
		_isr_hook();
		_isr_hook = 0;
	}
}

INT32S drv_l1_rotarot_format_set(INT32U format)
{
	INT32U	reg = get_ROTATOR_Reg_Base()->ROTATOR_CTRL;

	reg &= ~FORMAT_MASK;
	reg &= ~YUV422_MASK;

	switch(format)
	{
	case IMAGE_RGB565:
		reg |= FORMAT_RGB565;
		break;

	case IMAGE_GP420:
		reg |= FORMAT_GP420;
		break;

	default:
		reg |= FORMAT_YUV422;

		switch(format)
		{
		case IMAGE_YUYV:
			reg |= YUV422_YUYV;
			break;

		case IMAGE_YVYU:
			reg |= YUV422_YVYU;
			break;

		case IMAGE_UYVY:
			reg |= YUV422_UYVY;
			break;

		case IMAGE_VYUY:
			reg |= YUV422_VYUY;
			break;

		default:
			return -1;
			break;
		}

		break;
	}

	get_ROTATOR_Reg_Base()->ROTATOR_CTRL = reg;

	return 0;
}

INT32S drv_l1_rotator_pixel_set(INT32U w, INT32U h)
{
	get_ROTATOR_Reg_Base()->ROTATOR_IMG_WIDTH = (w & PIXEL_W_MASK);
	get_ROTATOR_Reg_Base()->ROTATOR_IMG_HEIGHT = (h & PIXEL_H_MASK);

	return 0;
}

INT32S drv_l1_rotator_module_enable(INT32U enable)
{
	INT32U	reg = get_ROTATOR_Reg_Base()->ROTATOR_CTRL;

	reg &= ~ROT_MODULE_MASK;

	if(enable)
	{
		reg |= ROT_MODULE_ENABLE;
	}
	else
	{
		reg |= ROT_MODULE_DISABLE;
	}

	get_ROTATOR_Reg_Base()->ROTATOR_CTRL = reg;

	return 0;
}

INT32S drv_l1_rotator_mode_set(INT32U mode)
{
	INT32U	reg = get_ROTATOR_Reg_Base()->ROTATOR_CTRL;

	reg &= ~ROT_MODE_MASK;

	switch(mode)
	{

	case ROTATOR_90:
		reg |= ROT_MODE_90;
		break;

	case ROTATOR_180:
		reg |= ROT_MODE_180;
		break;

	case ROTATOR_270:
		reg |= ROT_MODE_270;
		break;

	case ROTATOR_HORIZONTAL_MIRROR:
		reg |= ROT_MODE_H_MIRR;
		break;

	case ROTATOR_VERTICAL_MIRROR:
		reg |= ROT_MODE_V_MIRR;
		break;

	case ROTATOR_270_VERTICAL_MIRROR:
		reg |= ROT_MODE_270_V_MIRR;
		break;

	case ROTATOR_90_VORIZONTAL_MIRROR:
		reg |= ROT_MODE_90_V_MIRR;
		break;
	}

	get_ROTATOR_Reg_Base()->ROTATOR_CTRL = reg;

	return 0;
}

INT32S drv_l1_rotator_burst16_enable(INT32U enable)
{
	INT32U	reg = get_ROTATOR_Reg_Base()->ROTATOR_CTRL;

	reg &= ~ROT_BURST_MASK;

	if(enable)
	{
		reg |= ROT_BURST_16;
	}
	else
	{
		reg |= ROT_BURST_8;
	}

	get_ROTATOR_Reg_Base()->ROTATOR_CTRL = reg;

	return 0;
}

INT32S drv_l1_rotator_start(void (*isr_hook)(void))
{
#if SYSTEM_OS_ENABLE == 0
	rotator_end = 1;
#endif
	drv_l1_rotator_lock();
	_isr_hook = isr_hook;
	get_ROTATOR_Reg_Base()->ROTATOR_START = 0x1;
	drv_l1_rotator_unlock();

	return 0;
}

INT32S drv_l1_rotator_end_wait(INT32U wait)
{
	INT32S	state = -1;

	drv_l1_rotator_lock();
	if(wait)
	{
#if SYSTEM_OS_ENABLE == 1
		INT8U	error;
		state = (INT32S) OSQPend(rotator_q, 5000, &error);
#elif SYSTEM_OS_ENABLE == 2
		osEvent result;
		result = osMessageGet(rotator_q, 5000);
		state = result.value.v;
#else
		while(rotator_end);
#endif
	}

	drv_l1_rotator_unlock();

#if SYSTEM_OS_ENABLE == 0
	state = rotator_end;
#endif
	return state;
}

INT32S drv_l1_rotator_is_busy(void)
{
	return(get_ROTATOR_Reg_Base()->ROTATOR_START & 0x1) ? 1 : 0;
}

INT32S drv_l1_rotator_input_buffer_set(INT32U buf)
{
	get_ROTATOR_Reg_Base()->ROTATOR_BUF_I_ADDR = buf;
	get_ROTATOR_Reg_Base()->ROTATOR_BUF_I_ADDR2 = buf;

	return 0;
}

INT32U drv_l1_rotator_input_buffer_get(void)
{
	return get_ROTATOR_Reg_Base()->ROTATOR_BUF_I_ADDR;
}

INT32S drv_l1_rotator_output_buffer_set(INT32U buf)
{
	get_ROTATOR_Reg_Base()->ROTATOR_BUF_O_ADDR = buf;

	return 0;
}

INT32U drv_l1_rotator_output_buffer_get(void)
{
	return get_ROTATOR_Reg_Base()->ROTATOR_BUF_O_ADDR;
}

static INT32S drv_l1_rotator_buffer_mode(INT32U mode)
{
	INT32U	reg = get_ROTATOR_Reg_Base()->ROTATOR_CTRL;

	reg &= ~BUFFER_MODE_MASK;

	switch(mode)
	{
	case ROT_BUFFER_MODE_SHADOW:
		reg |= BUFFER_MODE_SHADOW;
		break;

	case ROT_BUFFER_MODE_AB:
		reg |= BUFFER_MODE_AB;
		break;
	}

	get_ROTATOR_Reg_Base()->ROTATOR_CTRL = reg;

	return 0;
}

INT32S drv_l1_rotator_init(void)
{
	get_ROTATOR_Reg_Base()->ROTATOR_CTRL = 0;

	drv_l1_rotator_buffer_mode(ROT_BUFFER_MODE_AB);

	// Clear Rotator pending interrupts
	get_ROTATOR_Reg_Base()->ROTATOR_IRQ_STATUS = C_RPTATOR_INT_END;
	get_ROTATOR_Reg_Base()->ROTATOR_IRQ_EN = C_RPTATOR_INT_EN;

#if SYSTEM_OS_ENABLE == 1
	if(rotator_q == NULL)
	{
		rotator_q = OSQCreate(&rotator_q_buffer[0], C_ROTATOR_QUEUE_SIZE);
	}

	if(rotator_hw_sem == NULL)
	{
		rotator_hw_sem = OSSemCreate(1);
	}

#elif SYSTEM_OS_ENABLE == 2
	if(rotator_q == NULL)
	{
		osMessageQDef_t rot_q = { C_ROTATOR_QUEUE_SIZE, sizeof(INT32U), 0 };

		rotator_q = osMessageCreate(&rot_q, NULL);
	}

	if(rotator_hw_sem == NULL)
	{
		osSemaphoreDef_t	rotator_sem = { 0 };

		rotator_hw_sem = osSemaphoreCreate(&rotator_sem, 1);
	}

#else
	rotator_end = 0;
#endif
#if SYSTEM_OS_ENABLE == 2
	NVIC_SetPriority(ROTATOR_IRQn, 5);
	NVIC_EnableIRQ(ROTATOR_IRQn);
#else
	vic_irq_register(VIC_ROT, ROTATOR_IRQHandler);
	vic_irq_enable(VIC_ROT);
#endif
	return 0;
}

INT32S drv_l1_rotator_line_buf_enable(INT32U en)
{

	return 0;
}
INT32S drv_l1_rotator_sw_reset(void)
	{
	INT16U timeOutCount = 0;
	get_ROTATOR_Reg_Base()->ROTATOR_SW_RESET= ROT_SW_RESET_SET;

	do
	{
		if(timeOutCount >= 0xFFFF)
	{
			return 1;
	}

		timeOutCount++;
	}while(get_ROTATOR_Reg_Base()->ROTATOR_SW_RESET & ROT_SW_RESET_SET);
	return 0;
}

#endif // _DRV_L1_ROTATOR
